package com.rtsapp.server.benchmark.cases.cmd;

import com.rtsapp.server.benchmark.AbstractTestCase;
import com.rtsapp.server.benchmark.cases.asst.AssertInfo;
import com.rtsapp.server.benchmark.cases.asst.AssertUtils;
import com.rtsapp.server.benchmark.runner.ContextUtils;
import com.rtsapp.server.common.IByteBuffer;
import com.rtsapp.server.logger.LoggerFactory;
import com.rtsapp.server.network.protocol.command.ICommand;
import com.rtsapp.server.profiling.Profilling;
import com.rtsapp.server.logger.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by admin on 15-9-11.
 */
public class CommandCase extends AbstractTestCase implements ICommandCase {

    private static final Logger LOGGER = LoggerFactory.getLogger(CommandCase.class);

    private CommandCaseHandler handler;
    private final ICommand request;
    private final ICommand response;
    private final String requestAttrKey;
    private final String responseAttrKey;

    private List<AssertInfo> assertList;

    public CommandCase( Map context, long delayTime, ICommand request, ICommand response , String reqeustAttrKey, String responseAttrKey ){
        super( context, delayTime );

        this.request = request;
        this.response = response;
        this.requestAttrKey = reqeustAttrKey;
        this.responseAttrKey = responseAttrKey;
    }


    /**
     * 给命令添加一个断言
     * @param assertInfo
     */
    public void addAssertInfo( AssertInfo assertInfo ){
        if( assertInfo == null ){
            return;
        }

        if( assertList == null ){
            assertList = new ArrayList<>( 3 );
        }

        assertList.add(assertInfo);
    }

    @Override
    public void start( ){
        super.start();

        send();
    }


    /**
     * 发送请求
     */
    private void send( ){

        if( requestAttrKey != null ){
            this.getContext().put(requestAttrKey, request);
        }


        LOGGER.debug("[{}]:发送请求: 0x{}" , ContextUtils.getContextId( this.getContext() ), Integer.toHexString(request.getCommandId()));
        handler.send(request);
    }


    @Override
    public void setHandler(CommandCaseHandler handler){
        this.handler = handler;
    }


    /**
     * 接收响应
     * @param commandId 命令id
     * @param buffer 网络响应
     * @return true 表示接收到了期望的消息, false表示没有接收到期望的消息
     */
    @Override
    public boolean recieve(int commandId, IByteBuffer buffer){

        if( commandId == response.getCommandId() ){
            LOGGER.debug("[{}]:接收响应:0x{}", ContextUtils.getContextId(this.getContext()), Integer.toHexString(response.getCommandId()));
            response.readFromBuffer(buffer);
            return true;
        }else{
            return false;
        }

    }

    /**
     * 接收到响应后继续执行
     */
    @Override
    public void continueExecute(){

        if( responseAttrKey != null ){
            this.getContext().put(responseAttrKey, response);
        }

        asset();

        complete();

    }




    /**
     * 断言测试
     */
    private void asset( ){

        long commandRTT =  System.nanoTime() - startTime;
        boolean hasError = false;

        if( assertList != null && assertList.size() > 0 ){

            for( AssertInfo assertInfo : assertList ){
                //每个断言try，catch一次，保证其他测试用例还能执行
                try {
                    AssertUtils.doAssert(assertInfo, this.getContext() , response );
                }catch( Throwable ex){
                    hasError = true;
                    LOGGER.error( ex , "[{}]: CommandCase {}, assert断言出错, assertInfo={}",   ContextUtils.getContextId( getContext() ), this.getResponse().getClass().getSimpleName(),  assertInfo );
                }
            }

        }


        if( hasError ){
            Profilling.getInstance().getExecuteProfilling( Profilling.CategoryIds.BENCHMARK_COMMAND, request.getCommandId() ).logFail( );
        }else{
            Profilling.getInstance().getExecuteProfilling( Profilling.CategoryIds.BENCHMARK_COMMAND, request.getCommandId() ).logSuccess( commandRTT );
        }


    }


    @Override
    public ICommand getRequest() {
        return request;
    }

    @Override
    public ICommand getResponse() {
        return response;
    }

    public String getRequestAttrKey() {
        return requestAttrKey;
    }

    public String getResponseAttrKey() {
        return responseAttrKey;
    }

    public List<AssertInfo> getAssertList() {
        return assertList;
    }
}
